package com.d2rv.settings;

import processing.core.PVector;

/**
 * Describes the settings of the application
 *
 * @author Darrieutort A., Dupouy A., Rossignol L., Van Poucke A.
 */
public class Settings {

    //Calibration
    private float screenwidth;
    private float screenheight;
    private float distancekinectfloor;
    private float userrecoil;
    private float distancekinecttv;
    private float offseteyes;
    //GameOption
    private PVector movespeed;
    private PVector rotatespeed;
    private int headtracking;
    private int gesturemode;
    private int delayinstruction;
    //Multisampling
    private int levelmutlisampling;
    //Light
    private PVector lightposition;
    private PVector lighttarget;
    //Modele3D
    private String cityname;
    private String citymapname;
    private PVector cityscale;
    private PVector cityposition;
    //Skybox
    private int skyboxhalfsize;
    //VRPN
    private String vrpnip;
    
    private String path;
    private JDomParser parser;
    private static final Settings instance = new Settings();

    /**
     * Default constructor.
     */
    private Settings() {
        this.screenwidth = 0;
        this.screenheight = 0;
        this.distancekinectfloor = 0;
        this.userrecoil = 0;
        this.distancekinecttv = 0;
        this.offseteyes = 0;
        this.movespeed = new PVector(0, 0, 0);
        this.rotatespeed = new PVector(0, 0, 0);
        this.headtracking = 0;
        this.gesturemode = 0;
        this.delayinstruction = 0;
        this.levelmutlisampling = 0;
        this.lightposition = new PVector(0, 0, 0);
        this.lighttarget = new PVector(0, 0, 0);
        this.cityname = "";
        this.cityscale = new PVector(0, 0, 0);
        this.cityposition = new PVector(0, 0, 0);
        this.skyboxhalfsize = 0;
        this.vrpnip = "";
        this.path = "";
        this.parser = null;
    }

    /**
     * Initializes the settings of th application
     *
     * @param path the path of the file to load
     */
    public void init(String path) {
        if (this.parser == null) {
            this.path = path;
            try {
                this.parser = new JDomParser(this.path);
            } catch (Exception e) {
                System.err.println("Unexpected JDomParser error : " + e.getMessage());
            }
            this.load();
        }
    }

    /**
     * Loads all the values of the file in the differents attributes
     */
    public void load() {
        try {
            this.screenwidth = Float.parseFloat(parser.getElement("Calibration", "ScreenWidth"));
            this.screenheight = Float.parseFloat(parser.getElement("Calibration", "ScreenHeight"));
            this.distancekinectfloor = Float.parseFloat(parser.getElement("Calibration", "DistanceKinectFloor"));
            this.userrecoil = Float.parseFloat(parser.getElement("Calibration", "UserRecoil"));
            this.distancekinecttv = Float.parseFloat(parser.getElement("Calibration", "DistanceKinectTV"));
            this.offseteyes= Float.parseFloat(parser.getElement("Calibration", "OffsetEyes"));
            this.movespeed.x = Float.parseFloat(parser.getElement("GameOption", "MoveSpeedX"));
            this.movespeed.y = Float.parseFloat(parser.getElement("GameOption", "MoveSpeedY"));
            this.movespeed.z = Float.parseFloat(parser.getElement("GameOption", "MoveSpeedZ"));
            this.rotatespeed.x = Float.parseFloat(parser.getElement("GameOption", "RotateX"));
            this.rotatespeed.y = Float.parseFloat(parser.getElement("GameOption", "RotateY"));
            this.rotatespeed.z = Float.parseFloat(parser.getElement("GameOption", "RotateZ"));
            this.headtracking = Integer.parseInt(parser.getElement("GameOption", "HeadTracking"));
            this.gesturemode = Integer.parseInt(parser.getElement("GameOption", "GestureMode"));
            this.delayinstruction = Integer.parseInt(parser.getElement("GameOption", "DelayInstruction"));
            this.levelmutlisampling = Integer.parseInt(parser.getElement("Multisampling", "Level"));
            this.lightposition.x = Float.parseFloat(parser.getElement("Light", "PositionX"));
            this.lightposition.y = Float.parseFloat(parser.getElement("Light", "PositionY"));
            this.lightposition.z = Float.parseFloat(parser.getElement("Light", "PositionZ"));
            this.lighttarget.x = Integer.parseInt(parser.getElement("Light", "TargetX"));
            this.lighttarget.y = Integer.parseInt(parser.getElement("Light", "TargetY"));
            this.lighttarget.z = Integer.parseInt(parser.getElement("Light", "TargetZ"));
            this.cityname = parser.getElement("Modele3D", "Name");
            this.citymapname = parser.getElement("Modele3D", "Map");
            this.cityscale.x = Integer.parseInt(parser.getElement("Modele3D", "ScaleX"));
            this.cityscale.y = Integer.parseInt(parser.getElement("Modele3D", "ScaleY"));
            this.cityscale.z = Integer.parseInt(parser.getElement("Modele3D", "ScaleZ"));
            this.cityposition.x = Float.parseFloat(parser.getElement("Modele3D", "PositionX"));
            this.cityposition.y = Float.parseFloat(parser.getElement("Modele3D", "PositionY"));
            this.cityposition.z = Float.parseFloat(parser.getElement("Modele3D", "PositionZ"));
            this.skyboxhalfsize = Integer.parseInt(parser.getElement("Skybox", "HalfSize"));
            this.vrpnip = parser.getElement("VRPN", "IP");
        } catch (Exception e) {
            System.err.println("Unexpected parsing error of settings file : " + e.getMessage());
        }
    }

    /**
     * Returns an instance of the class
     * @return an instance of the class
     */
    public static Settings getInstance() {
        return instance;
    }

    /**
     * Returns the height of the screen
     * @return the height of the screen
     */
    public float screenheight() {
        return this.screenheight;
    }

    /**
     * Returns the width of the screen
     * @return the width of the screen
     */
    public float screenwidth() {
        return this.screenwidth;
    }

    /**
     * Returns the space between the kinect and the floor
     * @return the space between the kinect and the floor
     */
    public float distancekinectfloor() {
        return this.distancekinectfloor;
    }

    /**
     * Returns the recoil of the user to the kinect
     * @return the recoil of the user to the kinect
     */
    public float userrecoil() {
        return this.userrecoil;
    }
    
    /**
     * Returns the space between the kinect and the tv
     * @return the space between the kinect and the floor
     */
    public float distancekinecttv() {
        return this.distancekinecttv;
    }
    
    /**
     * Returns the space between eyes
     * @return the space between the kinect and the floor
     */
    public float offseteyes() {
        return this.offseteyes;
    }

    /**
     * Returns the coefficient of speed
     * @return the coefficient of speed
     */
    public PVector movespeed() {
        return this.movespeed;
    }
    
    /**
     * Returns the coefficient of speed for rotation
     * @return the coefficient of speed
     */
    public PVector rotatespeed() {
        return this.rotatespeed;
    }

    /**
     * Returns the boolean that indicates if the user uses the head tracking or not
     * @return the boolean that indicates if the user uses the head tracking or not
     */
    public int headtracking() {
        return this.headtracking;
    }

    /**
     * Returns the mode of the gesture used
     * @return the mode of the gesture used
     */    
    public int gesturemode() {
        return this.gesturemode;
    }
    
    /**
     * Returns the time to display instruction
     * @return the mode of the gesture used
     */    
    public int delayinstruction() {
        return this.delayinstruction;
    }

    /**
     * Returns the multisampling level used in the application
     * @return the multisampling level used in the application
     */
    public int levelmutlisampling() {
        return this.levelmutlisampling;
    }

    /**
     * Returns the light position in the scene
     * @return the light position in the scene
     */
    public PVector lightposition() {
        return this.lightposition;
    }

    /**
     * Returns the target of the light in the scene
     * @return the color of the light in the scene
     */
    public PVector lighttarget() {
        return this.lighttarget;
    }

    /**
     * Returns the name of the city file
     * @return the name of the city file
     */
    public String cityname() {
        return this.cityname;
    }

    /**
     * Returns the name of the collisionMap file
     * @return the name of the collisionMap file
     */
    public String citymapname() {
        return this.citymapname;
    }

    /**
     *  Returns the scale of the city
     * @return the scale of the city
     */
    public PVector cityscale() {
        return this.cityscale;
    }

    /**
     * Returns the position of the city 
     * @return the position of the city
     */
    public PVector cityposition() {
        return this.cityposition;
    }
    
    /**
     * Returns the skybox halfsize
     * @return the skybox halfsize
     */
    public int skyboxhalfsize() {
        return this.skyboxhalfsize;
    }

    /**
     * Returns the ip used for the vrpn server
     * @return the ip used for the vrpn server
     */
    public String vrpnip() {
        return this.vrpnip;
    }
}
